package com.lonewalker.snail.service.impl;

import com.lonewalker.snail.common.base.ApiResult;
import com.lonewalker.snail.domain.request.AddAssigneeRequest;
import com.lonewalker.snail.domain.request.SequentialAddRequest;
import com.lonewalker.snail.service.ExtendService;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.history.HistoricActivityInstance;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.runtime.ActivityInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.FlowNode;
import org.camunda.bpm.model.bpmn.instance.SequenceFlow;
import org.camunda.bpm.model.bpmn.instance.UserTask;
import org.camunda.bpm.model.xml.instance.ModelElementInstance;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author lonewalker
 */
@Service
public class ExtendServiceImpl implements ExtendService {
    @Resource
    private HistoryService historyService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    @Resource
    private RepositoryService repositoryService;


    /**
     * <p>
     *     <li>思路是让流程实例从当前节点前的连线重启，但是当前节点前连线可能有多条,所以这里先查询历史环节，确保历史环节id包含连线的起始节点id。</li>
     *     <li>重启出现的问题：原先节点上是a,b审批。在a,b中间加了c，重启后节点上的任务会变成a,b,a,c,b
     *     所以首先要把当前节点的任务删除，重启后判断原先是否已有完成的任务，有则自动审批通过
     *     </li>
     * </p>
     *
     *
     * @param requestParam 请求参数
     * @return 提示信息
     */
    @Override
    public ApiResult<String> addAssignee(SequentialAddRequest requestParam) {
        String processInstanceId = requestParam.getProcessInstanceId();
        List<HistoricActivityInstance> hisActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).finished().list();
        List<String> activityIds = hisActivityList.stream().map(HistoricActivityInstance::getActivityId).collect(Collectors.toList());
        org.camunda.bpm.engine.runtime.ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        BpmnModelInstance bpmnModel = repositoryService.getBpmnModelInstance(processInstance.getProcessDefinitionId());
        ModelElementInstance modelElement = bpmnModel.getModelElementById(requestParam.getNodeId());
        UserTask userTask = (UserTask) modelElement;
        Collection<SequenceFlow> incoming = userTask.getIncoming();
        String transitionId = "";
        for (SequenceFlow sequenceFlow : incoming) {
            FlowNode source = sequenceFlow.getSource();
            if (activityIds.contains(source.getId())) {
                transitionId = sequenceFlow.getId();
                break;
            }
        }

        //获取当前环节实例
        ActivityInstance activity = runtimeService.getActivityInstance(processInstanceId);
        runtimeService.createProcessInstanceModification(processInstanceId)
                .cancelActivityInstance(activity.getId())
                .startTransition(transitionId)
                .execute();

        List<HistoricTaskInstance> hisTasks = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId)
                .taskDefinitionKey(requestParam.getNodeId()).taskDeleteReason("completed").list();
        List<String> assignees = hisTasks.stream().map(HistoricTaskInstance::getAssignee).collect(Collectors.toList());
        //之前已完成的任务此时自动审批
        automaticPass(processInstanceId, requestParam.getNodeId(), assignees);
        hisTasks.forEach(hisTask -> historyService.deleteHistoricTaskInstance(hisTask.getId()));

        return ApiResult.successMessage("加签成功");
    }

    private void automaticPass(String processInstanceId,String targetNodeId, List<String> assignees){
        Task runTask = taskService.createTaskQuery().processInstanceId(processInstanceId).taskDefinitionKey(targetNodeId).singleResult();
        if (assignees.contains(runTask.getAssignee())){
            taskService.complete(runTask.getId());
            automaticPass(processInstanceId,targetNodeId,assignees);
        }
    }
}
